package cn.antcore.resources.core;

import cn.antcore.resources.AutoRefresh;
import cn.antcore.resources.config.RefreshConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.framework.Advised;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;

/**
 * 刷新Bean
 * Created By Hong on 2018/8/7
 **/
@Component(value = "BeanRefresher")
public class BeanRefresher implements RefreshConfig {

    private static final Logger LOG = LoggerFactory.getLogger(BeanRefresher.class);

    private ConfigurableApplicationContext context;

    public BeanRefresher(ConfigurableApplicationContext context) {
        this.context = context;
    }

    @Override
    public synchronized void refresh() {
        DefaultListableBeanFactory factory = (DefaultListableBeanFactory) this.context.getAutowireCapableBeanFactory();
        String[] names = factory.getBeanNamesForAnnotation(AutoRefresh.class);
        for (String name : names) {
            Object target = this.context.getBean(name);
            if (AopUtils.isAopProxy(target)) {
                target = getTargetObject(target);
            }
            BeanDefinitionRegistry registry = factory;

            BeanDefinition definition = registry.getBeanDefinition(name);

            BeanDefinitionBuilder definitionBuilder = BeanDefinitionBuilder.rootBeanDefinition(target.getClass());
            AbstractBeanDefinition abstractBeanDefinition = definitionBuilder.getBeanDefinition();
            //用新的BeanDefinition把就的的BeanDefinition中
            abstractBeanDefinition.overrideFrom(definition);

            //重新注册
            registry.registerBeanDefinition(name, abstractBeanDefinition);

            if (LOG.isDebugEnabled()) {
                LOG.debug("Refresh Bean " + name + " Successful.");
            }
        }
        if (LOG.isInfoEnabled()) {
            LOG.info("Refresh Beans Successful.");
        }
    }

    /**
     * 获取aop代理的目标对象
     *
     * @param candidate 源对象
     * @param <T>       目标对象
     * @return 目标对象
     */
    private static <T> T getTargetObject(Object candidate) {
        try {
            if (AopUtils.isAopProxy(candidate) && (candidate instanceof Advised)) {
                return (T) ((Advised) candidate).getTargetSource().getTarget();
            }
        } catch (Exception ex) {
            throw new IllegalStateException("Failed to unwrap proxied object", ex);
        }
        return (T) candidate;
    }
}
